use af_db::{get_all_profiles, get_profile_by_name, init_db, save_profile};
use af_down::{download_version, get_version_manifest};
use af_util::{MinecraftProfile, Version};
use ntex::web::{self, types::Json};
use tokio::process::{Child, Command};

#[web::get("/profiles/{name}")]
async fn get1profile(name: web::types::Path<String>) -> Result<impl web::Responder, web::Error> {
    let p = get_profile_by_name(&name)
        .map_err(|e| web::error::ErrorInternalServerError(e.to_string()))?
        .ok_or(web::error::ErrorNotFound(format!(
            "No profile named {}",
            name
        )))?;

    Ok(Json(p))
}

#[web::get("/profiles")]
async fn get_profiles() -> Result<impl web::Responder, web::Error> {
    let profiles =
        get_all_profiles().map_err(|e| web::error::ErrorInternalServerError(e.to_string()))?;
    Ok(Json(profiles))
}

#[web::post("/profiles/{name}")]
async fn post_profile(
    name: web::types::Path<String>,
    body: Json<MinecraftProfile>,
) -> Result<impl web::Responder, web::Error> {
    if body.0.name != *name {
        return Err(web::error::ErrorBadRequest("Name mismatch").into());
    }
    save_profile(body.0).map_err(|e| web::error::ErrorInternalServerError(e.to_string()))?;
    Ok(web::HttpResponse::Ok())
}

#[web::get("/minecraft/versions")]
async fn get_mc_versions() -> Result<impl web::Responder, web::Error> {
    let versions = get_version_manifest()
        .await
        .map_err(|e| web::error::ErrorInternalServerError(e.to_string()))?;
    Ok(Json(versions))
}

#[web::get("/minecraft/versions/download")]
async fn get_mc_version_download(
    body: Json<Version>,
) -> Result<impl web::Responder, web::Error> {
    download_version(body.0)
        .await
        .map_err(|e| web::error::ErrorInternalServerError(e.to_string()))?;
    Ok(web::HttpResponse::Ok())
}

#[ntex::main]
async fn main() -> std::io::Result<()> {
    let _aria2 = start_arai2().await;
    init_db().map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
    web::HttpServer::new(|| {
        web::App::new()
            .service(get1profile)
            .service(get_profiles)
            .service(post_profile)
            .service(get_mc_versions)
            .service(get_mc_version_download)
    })
    .bind(("127.0.0.1", 3366))?
    .run()
    .await
}

pub async fn start_arai2() -> Child {
    Command::new("aria2c")
        .arg("--enable-rpc")
        .arg("--rpc-secret=af")
        .arg("--rpc-listen-all")
        .arg("--rpc-listen-port=6800")
        .arg("--daemon=false")
        .kill_on_drop(true)
        .spawn()
        .expect("failed to execute process")
}
